package com.tycoin.app.handler;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.fasterxml.jackson.core.JsonParseException;
import com.tycoin.common.bean.BaseResult;
import com.tycoin.common.bean.ResultCode;
import com.tycoin.common.exception.RestException;
import com.tycoin.common.exception.ServiceException;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

@ControllerAdvice
public class ApiExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(ApiExceptionHandler.class);

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(RestException.class)
    public @ResponseBody BaseResult handleException(RestException ex, WebRequest request, HttpServletResponse response) {
        logger.error("handle RestException : " + ex.getMessage(), ex);

        return new BaseResult(ex.getStatus());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({NumberFormatException.class, MethodArgumentTypeMismatchException.class, HttpMessageNotReadableException.class,
            IllegalAccessException.class, JsonParseException.class})
    public @ResponseBody BaseResult handleException(Exception ex, WebRequest request, HttpServletResponse response) {
        logger.error("handle Param parse Exception : " + ex.getMessage(), ex);
        if (StringUtils.isNotEmpty(ex.getMessage())) {
            return new BaseResult(ResultCode.ILLEGAL_ARGUMENT.value(), ex.getMessage());
        }
        return new BaseResult(ResultCode.ILLEGAL_ARGUMENT.value(), ResultCode.ILLEGAL_ARGUMENT.name());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ServiceException.class)
    public @ResponseBody BaseResult handleException(ServiceException ex, WebRequest request, HttpServletResponse response) {
        logger.error("handle ServiceException : " + ex.getMessage(), ex);
        if (StringUtils.isNotEmpty(ex.getMessage())) {
            return new BaseResult(ex.getCode(), ex.getMessage());
        }
        return new BaseResult(ex.getCode());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(NoHandlerFoundException.class)
    public @ResponseBody BaseResult handleException(NoHandlerFoundException ex, WebRequest request, HttpServletResponse response) {
        logger.error("handle NoHandlerFoundException : " + ex.getMessage(), ex);

        return new BaseResult(HttpStatus.NOT_FOUND);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({ConstraintViolationException.class, DataIntegrityViolationException.class, MySQLIntegrityConstraintViolationException.class})
    public @ResponseBody BaseResult handleException(Exception ex, WebRequest request) {
        logger.error("handle Data Exception : " + ex.getMessage(), ex);

        return new BaseResult(HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Throwable.class)
    public @ResponseBody BaseResult handleException(Throwable ex, WebRequest request, HttpServletResponse response) {
        logger.error("handle Throwable : " + ex.getMessage(), ex);

        return new BaseResult(HttpStatus.INTERNAL_SERVER_ERROR);
    }

}